#include <linux/module.h>
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/msi.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include "drv_pcie_flash.h"

#define FLASH_READ_DONE_MASK        0x02    /* 读完成 掩码 */
#define FLASH_WRITE_DONE_MASK       0x01    /* 写完成 掩码 */
#define FLASH_READ_DONE_SHIFT       1       /* 读完成 偏移 */
#define FLASH_WRITE_DONE_SHIFT      0       /* 写完成 偏移 */

#define FLASH_OP_TIMEOUT_MS         1000    /* 操作超时时间 */
#define FLASH_POLL_INTERVAL_US      10      /* 轮询间隔 */

/* 寄存器*/
enum flash_reg_t {
    FLASH_WRITE_ADDR_REG    = 0x84,         /* 写地址 寄存器 */
    FLASH_WRITE_DATA_REG    = 0x88,         /* 写数据 寄存器 */
    FLASH_READ_ADDR_REG     = 0x8c,         /* 读地址 寄存器 */
    FLASH_READ_DATA_REG     = 0x90,         /* 读数据 寄存器 */
    FLASH_READ_STA_REG      = 0x94,         /* 读状态 寄存器 */
};

/* 文件操作函数声明 */
static int open_flash(struct inode *inode, struct file *filp);
static int release_flash(struct inode *inode, struct file *filp);
static long ioctl_flash(struct file *filp, unsigned int cmd, 
                     unsigned long arg);

/* 文件操作结构体 */
static const struct file_operations cdev_fops = {
    .owner = THIS_MODULE,
    .open = open_flash,
    .release = release_flash,
    .read = NULL,
    .write = NULL,
    .unlocked_ioctl = ioctl_flash,
    .poll = NULL,
    .llseek = no_llseek,
};

/* 读取寄存器 */
static u32 read_flash_reg_le(struct pcie_dev_t *ppdev, u32 reg)
{
    u32 val = 0;
    unsigned long flags = 0;    /* 用于保存中断状态 */

    /* 获取自旋锁(保存中断状态) */
    spin_lock_irqsave(&ppdev->splock, flags);
    val = ioread32(ppdev->bar[0] + reg);
    /* 释放自旋锁(恢复中断状态) */
    spin_unlock_irqrestore(&ppdev->splock, flags);
    pr_debug("%s  reg=0x%08x, val=0x%08x", __func__, reg, val);

    return val;
}

/* 写入寄存器 */
static void write_flash_reg_le(struct pcie_dev_t *ppdev, u32 reg, u32 val)
{
    unsigned long flags = 0;    /* 用于保存中断状态 */

    /* 获取自旋锁(保存中断状态) */
    spin_lock_irqsave(&ppdev->splock, flags);
    iowrite32(val, ppdev->bar[0] + reg);
    /* 释放自旋锁(恢复中断状态) */
    spin_unlock_irqrestore(&ppdev->splock, flags);
    pr_debug("%s reg=0x%08x, val=0x%08x", __func__, reg, val);
}

/* 等待操作完成 */
static int wait_flash_ready(struct flash_ctrl_t *pctrl, u32 timeout_ms)
{
    struct pcie_dev_t *ppdev = pctrl->ppdev;
    unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
    u32 status;
    
    while (time_before(jiffies, timeout)) {
        status = read_flash_reg_le(ppdev, FLASH_READ_STA_REG);
        
        /* 检查读写完成标志 */
        if ((status & (FLASH_READ_DONE_MASK | FLASH_WRITE_DONE_MASK)) == 
            (FLASH_READ_DONE_MASK | FLASH_WRITE_DONE_MASK)) {
            return 0;
        }
        
        /* 非阻塞检查，避免过度占用CPU */
        if (timeout_ms > 10) {
            usleep_range(FLASH_POLL_INTERVAL_US, FLASH_POLL_INTERVAL_US * 2);
        }
    }
    
    dev_err(pctrl->dev, "Flash operation timeout, status=0x%08x\n", status);
    return -ETIMEDOUT;
}

/* 从地址读取数据 */
static int read_flash(struct flash_ctrl_t *pctrl, u32 addr, 
                      u32 *data, u32 size)
{
    struct pcie_dev_t *ppdev = pctrl->ppdev;
    int ret = 0;
    u32 i;

    /* 检查参数 */
    if (!pctrl || !data || size == 0) {
        pr_err("Invalid parameters for %s", __func__);
        return -EINVAL;
    }
    if (addr < pctrl->start_addr || 
        addr + (size - 1) * sizeof(u32) > pctrl->end_addr) {
        dev_err(pctrl->dev, "%s: address 0x%08x size %u out of range\n", 
               __func__, addr, size);
        return -EFAULT;
    }
    /* 检查地址对齐 */
    if (addr & 0x3) {
        dev_err(pctrl->dev, "%s: unaligned address 0x%08x\n", __func__, addr);
        return -EINVAL;
    }

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "%s: acquire mutex failed\n", __func__);
        return -ERESTARTSYS;
    }
    
    /* 批量读取 */
    for (i = 0; i < size; i++) {
        write_flash_reg_le(ppdev, FLASH_READ_ADDR_REG, addr + i * sizeof(u32));
        
        /* 等待读操作完成 */
        ret = wait_flash_ready(pctrl, FLASH_OP_TIMEOUT_MS);
        if (ret) {
            dev_err(pctrl->dev, "%s: read timeout at 0x%08x\n", 
                   __func__, addr + i * sizeof(u32));
            break;
        }
        
        data[i] = read_flash_reg_le(ppdev, FLASH_READ_DATA_REG);
    }
    
    mutex_unlock(&pctrl->lock);
    return ret;
}

/* 向地址写入数据 */
static int write_flash_bulk(struct flash_ctrl_t *pctrl, u32 addr, 
                           const u32 *data, u32 size)
{
    struct pcie_dev_t *ppdev = pctrl->ppdev;
    int ret = 0;
    u32 i;
    
    /* 检查参数 */
    if (!data || size == 0) {
        dev_err(pctrl->dev, "%s: invalid parameters\n", __func__);
        return -EINVAL;
    }
    
    if (addr < pctrl->start_addr || 
        addr + (size - 1) * sizeof(u32) > pctrl->end_addr) {
        dev_err(pctrl->dev, "%s: address 0x%08x size %u out of range\n", 
               __func__, addr, size);
        return -EFAULT;
    }
    
    /* 检查地址对齐 */
    if (addr & 0x3) {
        dev_err(pctrl->dev, "%s: unaligned address 0x%08x\n", __func__, addr);
        return -EINVAL;
    }
    
    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "%s: acquire mutex failed\n", __func__);
        return -ERESTARTSYS;
    }
    
    /* 批量写入 */
    for (i = 0; i < size; i++) {
        write_flash_reg_le(ppdev, FLASH_WRITE_ADDR_REG, addr + i * sizeof(u32));
        write_flash_reg_le(ppdev, FLASH_WRITE_DATA_REG, data[i]);
        
        /* 等待写操作完成 */
        ret = wait_flash_ready(pctrl, FLASH_OP_TIMEOUT_MS);
        if (ret) {
            dev_err(pctrl->dev, "%s: write timeout at 0x%08x\n", 
                   __func__, addr + i * sizeof(u32));
            break;
        }
    }
    
    mutex_unlock(&pctrl->lock);
    return ret;
}

/* 打开设备 */
static int open_flash(struct inode *inode, struct file *filp)
{
    /* 获取与 inode 关联的字符设备 */
    struct cdev_dev_t *cdev_dev = container_of(inode->i_cdev, struct cdev_dev_t, cdev);
    struct cdev_ctrl_t *cdev_ctrl = (struct cdev_ctrl_t *)(cdev_dev->parent);
    struct flash_ctrl_t *pctrl = (struct flash_ctrl_t *)(cdev_ctrl->parent);
    struct flash_dev_t *priv = &pctrl->flash[cdev_dev->index];

    /* 检查设备是否有效 */
    if (!priv || !priv->dev) {
        pr_err("Invalid parameters for %s", __func__);
        return -ENODEV;
    }
    /* 记录设备指针 */
    filp->private_data = priv;
    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&priv->lock)) {
        dev_err(priv->dev, "Acquire %s mutex failed", cdev_dev->name);
        return -ERESTARTSYS;
    }
    dev_dbg(priv->dev, "Open %s%d device", cdev_ctrl->name, cdev_dev->index);

    mutex_unlock(&priv->lock);

    return 0;
}

/* 关闭设备 */
static int release_flash(struct inode *inode, struct file *filp)
{
    struct flash_dev_t *priv = filp->private_data;

    if (priv) {
        mutex_lock(&priv->lock);
        dev_dbg(priv->dev, "Release %s device", priv->name);
        mutex_unlock(&priv->lock);
    }

    return 0;
}

/* IOCTL 处理 */
static long ioctl_flash(struct file *filp, unsigned int cmd, 
                     unsigned long arg)
{
    struct flash_dev_t *priv = filp->private_data;
    struct flash_ctrl_t *pctrl = (struct flash_ctrl_t *)(priv->parent);
    long ret = 0;

    /* 检查参数是否有效 */
    if (!priv || !priv->dev) {
        pr_err("Invalid parameters for %s", __func__);
        return -ENODEV;
    }

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&priv->lock)) {
        dev_err(priv->dev, "Acquire %s mutex failed", priv->name);
        return -ERESTARTSYS;
    }
    switch (cmd) {
    /* 从地址读取数据 */
    case IOCTL_FLASH_READ:
        if (copy_from_user(&u32_val, (void __user *)arg, sizeof(u32_val))) {
            dev_err(priv->dev, "Set all FLASH level copy failed");
            ret = -EFAULT;
            goto unlock;
        }
        set_all_flash_level(pctrl, u32_val);
        break;
    /* 向地址写入数据 */
    case IOCTL_FLASH_WRITE:
        ret = get_all_flash_level(pctrl, &u32_val);
        if (ret < 0) {
            dev_err(priv->dev, "Get all FLASH level 0x%08x failed", u32_val);
            ret = -EFAULT;
            goto unlock;
        }
        if (copy_to_user((void __user *)arg, &u32_val, sizeof(u32_val))) {
            dev_err(priv->dev, "Get all FLASH level 0x%08x copy failed", u32_val);
            ret = -EFAULT;
            goto unlock;
        }
        break;

    default:
        dev_err(priv->dev, "Ioctl FLASH%d cmd=0x%08x, dir=0x%X, size=%u, type=0x%02X('%c'), nr=%u not support\n",
                priv->index, cmd, _IOC_DIR(cmd), _IOC_SIZE(cmd), _IOC_TYPE(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd));
        ret = -ENOTTY;
        break;
    }

unlock:
    mutex_unlock(&priv->lock);

    return ret;
}

/* 初始化 FLASH 设备 */
static int init_flash_dev(void *parent, struct device *dev, const char *name, 
                       struct flash_dev_t *flash, u8 index)
{
    int ret = 0;

    flash->parent = parent;
    flash->dev = dev;
    /* 初始化互斥锁 */
    mutex_init(&flash->lock);
    strscpy(flash->name, name, sizeof(flash->name));
    flash->index = index;
    flash->mode = 0;
    flash->set_level = 0;
    flash->get_level = 0;
    flash->pulse.high = 0;
    flash->pulse.cycle = 0;
    flash->pulse.num = 0;
    flash->pulse_sta = 0;

    return ret;
}

/* 初始化 FLASH 控制器 */
int init_flash_ctrl(struct pcie_dev_t *ppdev, struct cdev_dev_t *pcdev, 
                    struct flash_ctrl_t *pctrl, struct flash_dev_t *pdev, 
                    const char *ctrl_name, u8 dev_num)
{
    int ret = 0;
    int i = 0;
    char name[32];

    pctrl->dev = &ppdev->pdev->dev;
    /* 初始化互斥锁 */
    mutex_init(&pctrl->lock);
    snprintf(pctrl->name, sizeof(pctrl->name), "%s", ctrl_name);
    pctrl->num = dev_num;
    pctrl->ppdev = ppdev;
    pctrl->read_reg = read_flash_reg_le;
    pctrl->write_reg = write_flash_reg_le;
    pctrl->cdev_ctrl.cdev_dev = cdev_dev;
    pctrl->flash = flash;

    /* 初始化字符设备 */
    ret = init_cdev_ctrl(pctrl, &pctrl->cdev_ctrl, pctrl->name, dev_num);
    if (ret < 0) {
        dev_err(pctrl->dev, "Init %s controller failed", pctrl->name);
        goto err_free_dev;
    }
    for (i = 0; i < dev_num; i++) {
        snprintf(name, sizeof(name), "%s%d", pctrl->name, i);
        ret = init_cdev_dev(&pctrl->cdev_ctrl, pctrl->cdev_ctrl.cclass, 
                            &pctrl->cdev_ctrl.cdev_dev[i], &cdev_fops, pctrl->cdev_ctrl.major_devno, name, i);
        if (ret) {
            dev_err(pctrl->dev, "Init %s device failed", name);
            goto err_cleanup_cdev_ctrl;
        }
    }

    /* 初始化 FLASH 设备*/
    for (i = 0; i < dev_num; i++) {
        init_flash_dev(pctrl, pctrl->dev, pctrl->cdev_ctrl.cdev_dev[i].name, 
                    &pctrl->flash[i], i);
    }

    return 0;

err_cleanup_cdev_ctrl:
    exit_cdev_ctrl(&pctrl->cdev_ctrl);
err_free_dev:

    return ret;
}

/* 注销 FLASH 控制器 */
void exit_flash_ctrl(struct flash_ctrl_t *pctrl, u8 dev_num)
{
    u8 i = 0;

    if (!pctrl) {
        pr_err("Invalid parameters for %s", __func__);
        return;
    }

    for (i = 0; i < dev_num; i++) {
        exit_cdev_dev(pctrl->cdev_ctrl.cclass, &pctrl->cdev_ctrl.cdev_dev[i]);
    }
    exit_cdev_ctrl(&pctrl->cdev_ctrl);
    dev_info(pctrl->dev, "Release cdev controller success");

    for (i = 0; i < dev_num; i++) {
        mutex_destroy(&pctrl->flash[i].lock);
    }
    /* 注销互斥锁 */
    mutex_destroy(&pctrl->lock);

    dev_info(pctrl->dev, "PCIe character device %s removed", pctrl->name);
}
